﻿using Coolzon.Common;
using Coolzon.UI.Core.Runtime.Script.Animation;
using Microsoft.ClearScript;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Coolzon.UI.Core.Runtime.Script
{
    public class ScriptEngine
    {
        private Dictionary<string, object> _addedObjectList = new Dictionary<string, object>();
        private List<string> _addedCodeList = new List<string>();

        public bool IsUsable = true;

        public string Name { get; private set; }

        private Microsoft.ClearScript.ScriptEngine _engine;

        public ScriptEngine(string name)
        {
            this.Name = name;
            _engine = new Microsoft.ClearScript.V8.V8ScriptEngine();
            _engine.AddHostObject("lib", new HostTypeCollection("mscorlib", "System.Core"));
            _engine.AddHostType("DelayAnimation", typeof(DelayAnimationScriptObject));
            _engine.AddHostType("FlyAnimation", typeof(FlyAnimationScriptObject));
            _engine.AddHostType("SequenceAnimation", typeof(SequenceAnimationScriptObject));
            _engine.AddHostType("ShowAnimation", typeof(ShowAnimationScriptObject));
            _engine.AddHostType("RotateAnimation", typeof(RotateAnimationScriptObject));
            _engine.AddHostType("ForeverAnimation", typeof(ForeverAnimationScriptObject));
            _engine.AddHostType("FuncAnimation", typeof(FuncAnimationScriptObject));

            _engine.Execute(@"function _runDataExpressionP2(expression, dataSeries, dataItem){
            var DataSeries = dataSeries;
            var DataItem = dataItem;
            return eval(expression);
        };");
        }


        public void Close()
        {
            _engine.CollectGarbage(true);
            _engine.Dispose();
        }
        public void Reset()
        {
            try
            {
                _engine.CollectGarbage(true);
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},reset出错ex:{1}", this.Name, ex));
            }
        }

        /// <summary>
        /// 添加代码到脚本引擎中
        /// </summary>
        /// <param name="code"></param>
        public void AddCode(string code)
        {
            _engine.Execute(code);
        }

        /// <summary>
        /// 往引擎中添加对象
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        public void AddObject(string name, object obj)
        {
            if (obj == null)
            {
                return;
            }
            _engine.AddHostObject(name, HostItemFlags.GlobalMembers, obj);
        }

        /// <summary>
        /// 向脚本引擎中添加脚本文件
        /// </summary>
        /// <param name="filePath">脚本文件</param>
        public void AddFile(string filePath)
        {
            try
            {
                _engine.Execute(File.ReadAllText(filePath));
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},读取脚本文件:{1}出错,ex:{2}", this.Name, filePath, ex));
            }
        }

        /// <summary>
        /// 执行一个表达式，返回表达式计算的结果
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public object RunExpression(string expression)
        {
            try
            {
                object result = _engine.Evaluate(expression);
                return result;
            }
            catch(Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 运行数据表达式
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="dataSeries"></param>
        /// <param name="dataItem"></param>
        /// <returns></returns>
        public bool RunDataExpressionToBoolean(string expression, object dataSeries, object dataItem)
        {
            bool ret = false;
            try
            {
                object result = _engine.Invoke("_runDataExpressionP2", expression, dataSeries, dataItem);
                if (result != null)
                {
                    ret = Convert.ToBoolean(result);
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本2:{1}出错,ex:{2}", this.Name, expression, ex));
            }
            return ret;
        }

        public bool RunExpressionToBoolean(string expression)
        {
            try
            {
                object result = _engine.Evaluate(expression);
                return (bool)result;
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本3:{1}出错,ex:{2}", this.Name, expression, ex));
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="func"></param>
        /// <param name="parameters"></param>
        public void Run(string func, params object[] parameters)
        {
            try
            {
                _engine.Invoke(func, parameters);
                _engine.CollectGarbage(true);
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},run {1}出错, ex:{2}!", this.Name, func, ex));
            }
        }
    }
}
